package a11_Network;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.MessageFormat;
import java.util.Scanner;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
 * @Author quan
 * @Description 服务端
 * @Date 2023/5/30 9:51
 */
public class TCPEchoServer {
    //声明一个用于服务端的Socket对象
    private ServerSocket server;

    /**
     * 通过指定端口号来实例化服务器
     * @param port 端口号
     * @throws IOException
     */
    public TCPEchoServer(int port) throws IOException {
        //端口的合法性校验
        if(port > 65535 || port < 1024){
            throw new RuntimeException("端口号要在1024-65535之间");
        }
        //实例化ServerSocket并制定端口
        this.server = new ServerSocket(port);
    }

    /**
     * 服务器开始工作
     * @throws IOException
     */
    public void start() throws IOException {
        System.out.println("服务器启动成功");
        /**
         *创建线程池来优化
         */
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3, 10, 1, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10));
        //1、循环接收客户端的输入
        while (true){
            //accept():如果有客户端连接就返回一个Socket对象，没有的话就阻塞等待
            Socket clientSocket = server.accept();
            /**
             * 处理多个客户端：多线程实现
             */
            //每次收到一个新连接请求，就创建一个新的子线程
//            Thread thread = new Thread(()->{
//                //2、服务器对接收到的客户端数据进行处理
//                try {
//                    processConnections(clientSocket);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            });
            //线程池中提交任务
            poolExecutor.submit(()->{
                try {
                    processConnections(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            //启动线程
//            thread.start();
        }
    }

    /**
     * 服务器对接收到的客户端数据进行处理
     * @param clientSocket 客户端数据
     */
    private void processConnections(Socket clientSocket) throws IOException {
        //打印日志：也可以使用printf方式打印
        String clientInfo = MessageFormat.format("[{0}:{1}] 客户端已经上线",clientSocket.getInetAddress(),clientSocket.getPort());
        System.out.println(clientInfo);
        //1、处理数据之前要先获取一下输入输出流
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()) {
            //2、循环处理用户的请求
            Scanner requestScanner = new Scanner(inputStream);
            while (true){
                //3、如果没有获取到用户输入：就说明客户端已经下线，关闭流并打印日志
                if(!requestScanner.hasNext()){
                    clientInfo = MessageFormat.format("[{0}:{1}] 客户端已经下线.",clientSocket.getInetAddress(),
                            clientSocket.getPort());
                    System.out.println(clientInfo);
                    break;
                }
                //4、获取真实的用户请求数据
                String request = requestScanner.nextLine();
                //4-1根据请求计算响应
                String respond = process(request);
                //5、将响应写回客户端（参考文件操作与IO一节：PrintWriter的使用）
                PrintWriter printWriter = new PrintWriter(outputStream);
                //5-1 写入输出流
                printWriter.println(respond);
                //5-2 强制刷新缓冲区
                printWriter.flush();
                //6、打印日志
                clientInfo = MessageFormat.format("[{0}:{1}],request:{2},response:{3}",
                        clientSocket.getInetAddress(),
                        clientSocket.getPort(),
                        request,
                        respond);
                System.out.println(clientInfo);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            clientSocket.close();
        }
    }

    /**
     * 接收客户端请求并返回：回显
     * @param request 客户端用户的请求
     * @return
     */
    private String process(String request) {
        return request;
        //改进为一个简单的消息回复
//        System.out.println("收到新消息");
//        Scanner sc = new Scanner(System.in);
//        String respond = sc.nextLine();
//        return respond;
    }

    public static void main(String[] args) throws IOException {
        TCPEchoServer server = new TCPEchoServer(9999);
        server.start();
    }
}
